home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 3: CDPD 3
/
Almathera Ten on Ten - Disc 3: CDPD3.iso
/
scope
/
051-075
/
scopedisk73
/
newsetfont
/
setfont.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-03-19
|
20KB
|
544 lines
/* ======================================================================= */
/* SetFont 2.0 -
by Dave Haynie (Hazy)
CIS: 76703,2047
Usenet: {allegra,caip,ihnp4}!cbmvax!daveh
Drink: Guiness
BUSINESS (MUNDANE, BUT IMPORTANT):
This program is written by me, Dave Haynie, as mentioned above.
I have, however, placed it in the PUBLIC DOMAIN. That, of course, means
that you can do (almost) absolutely anything with it. You may hack it
to bits, include it with YOUR product, sell it, GIVE IT AWAY, or anything
else you like. Of course, since anyone else can also give it away, it
would be foolish to stick your name on it and try to sell it. I really
would like everyone to give it away, nicely, without being mean about it.
If you want to use it with your product, do that too, new products for
the Amiga are generally a good thing for the entire Amiga community. You
can take bit and pieces and use them in your own programs, or the whole
thing for that matter. And if you really want to have fun, you can even
IMPROVE this program, as its far from perfect, and give YOUR version
away too, if you're so inclined. That's about it for the (mundane)
business section, let's get on to the (interesting) notes section.
ABOUT IT:
This program is designed to allow you to set the font of a console
window (or really, a general WorkBench window) to any font, ROM or disk
based, that you have in mind. This works much better than the first
version, in that it allows a greater variety of things to be changed
in the WorkBench. What, you say, a VARIETY of things? Well, lemme
explain....
First off, something about fonts. Amiga fonts all over the place
default to one of two ROM fonts, as specified in Preferences. A ROM font
is just a font that happens to stored in with the KickStart code, instead
of out on a disk. Since anything ever running on any Amiga can get to
these fonts, they're used very heavily, perhaps too much. If you've
ever used the NotePad, however, you will probably have used some other
fonts. These fonts are available on disk, and in fact, you can use
FontEd to create a variety of disk fonts for your own use.
Whether disk or ROM, most programs use the Amiga's font management
utilities, which are part of the KickStart based graphics library. But
very few folks just look at the graphics library. Most everyone looks
at Intuition. Intuition manages things like screens and windows, and
you can write things to both screens and windows. And, perhaps not
coincidentally, both screens and windows have some idea of what font they
should use, providing they've been given no special directions toward
using some other fonts. The screen stores a pointer to a critter called
a "TextAttr", which is essentially a DESCRIPTOR for a font. A TextAttr
contains the name of the font, the point size of the font, and a little
more information related to the font. Both screens and windows also
contains a graphics structure, called a RastPort, which points to the
memory used to store the displayed memory. The RastPort sports a pointer
to a different critter, the "TextFont". The is the actual font, which is
the result of passing a TextAttr to one of the font opening functions.
In this version I allow you to change the screen's font information,
like before, but I also know a bit more about the console window now.
When I open a window within a screen, such as the WorkBench screen,
it's RastPort gets its default font from the screen's TextAttr font
descriptor. If this window is going to be a console window, it will
built a ConUnit, which has its own idea of the current font, based on
the window. I can use the ROM Kernal SetFont() call to change the
font of the Window's RastPort. Then I send an "<ESC>c" to the console
which will reinitialize the ConUnit from the window (and also clear
the screen....oh well).
I need pointers to the window and screen to do this. Since the
Window structure contains a pointer to its screen, my goal is to find
the window associated with the calling console. The best way I've found
for this is by setting up the current console as an I/O item, then
calling the DOS Info() function, which will return a pointer to the
console's window. From this window I can get a the screen pointer and
the window's RastPort, so the fonts can be put in place. When the
Screen's TextAttr is changed, I only change the values of that font
descriptor that the user's asked me to change. Occasionally, this can
result in a few bytes of unreclaimed memory, as in font names: I have no
idea how much memory is reserved in the screen's TextAttr structure on
startup. I use the SetFont() function to set the window's or screen's
RastPort fonts.
There are a few problems with my scheme. First of all, many
programs are written to support only the topaz 8 (80 column) font. If
you're a 60 column user, you've probably experienced this before. Its
not a problem with the Amiga as a whole, since most of the system will
adjust itself. But it may be a problem with programs that have a fixed
idea of what a font should look like. Most 80 column fonts work with
most applications, and an 80 column 8x8 font will work just about
everywhere. Some programs, like CLI for instance, have trouble with
proportionally-spaced fonts. The best thing to to is try out the font
you like. One final problem is that some applications ask the
WorkBench screen to close when they start up. It'll close if there's
nothing else open on it, but when it re-opens, it'll restart with the
Preferences-selected font, not the SetFont selected font. Of course,
preferences doesn't support arbitrary fonts (which is why this program is
even necessary). Oh well, maybe in 1.3? The solution to this is to
always keep at least one window open, so that WorkBench will never be
closed on you.
*/
/* ======================================================================= */
/* Modifications -
by Keith Young, DAS Member (Devil's Advocate Software)
"We do Neat/Dangerous things... so you don't have to"
CIS: 73170,307
First off, thanks to Dave Haynie (Hazy) for supplying this little
dittie. In my never-ending quest to learn something new every day,
I've discovered a few things about how the system handles fonts and
made a few changes to SetFont that reflect these findings.
Most of the changes I've made have a /* ky /* in front of the change
as well as comments about them, so I won't repeat myself up here :).
The other changes that aren't marked are mostly casts to get the code
to compile cleanly with Manx and 16 bit ints. To compile/link with
Manx: 1> cc setfont
1> ln setfont -lc
There is still one place (font pointer) in the system that I have
not looked into completely... and that is GfxBase->DefaultFont.
According to the DevCon notes, this is updated anytime SetPrefs()
is called, but I'm not yet sure of it's significance. Whoops...
make that 2 places... IntuitionBase->Preferences->FontHeight is
the other... not sure what significance that has either (in the
grand scheme of things)
Cheers,
Keith
p.s. Keep in mind that this program pokes at INTUITIONPRIVATE
pointers, and so is not guarranteed to work with future
versions of the OS.
*/
#include <exec/types.h>
#include <exec/io.h>
#include <exec/ports.h>
#include <exec/memory.h>
#include <graphics/gfxbase.h>
#include <graphics/text.h>
#include <graphics/rastport.h>
#include <libraries/diskfont.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <libraries/diskfont.h>
#include <intuition/intuitionbase.h>
#include <stdio.h>
#include <functions.h> /* ky */
/* ========================================================================= */
/* External things */
/* ky */ /* these are in Manx's "functions.h" header file
extern struct Library *OpenLibrary();
extern struct TextFont *OpenFont();
extern struct TextFont *OpenDiskFont();
extern struct Window *OpenWindow();
*/
extern char *strcat();
extern char *strcpy();
extern long strlen();
/* ========================================================================= */
/* Global variables */
struct GfxBase *GfxBase = NULL;
struct Library *DiskfontBase = NULL;
struct IntuitionBase *IntuitionBase = NULL;
struct MsgPort portblk = {
{ 0, 0, NT_MSGPORT, 0, 0}, 0, -1, 0,
{(struct Node *)&portblk.mp_MsgList.lh_Tail, 0, (struct Node *)&portblk.mp_MsgList.lh_Head, 0, 0}
};
struct MsgPort *port = &portblk;
struct IOStdReq reqblk = {
{
{0, 0, 0, 0, 0},
&portblk, 0 }
, 0
};
struct IOStdReq *request = &reqblk;
struct Window *window = NULL;
struct Screen *screen = NULL;
/* ========================================================================= */
/* This section contains startup and shutdown functions. */
/* This function opens the required Amiga libraries, devices, and other
good stuff. It returns TRUE if successful. Graphics, Intuition, and
DiskFont libraries are opened. The console device is opened and the
I/O request message port is initialized. I also do a check to make sure
that the associated Task is really a Process. This is absolutely
necessary, as some of the functions that I'll be using later are DOS
functions, which require Processes, not Tasks. */
BOOL OpenUp()
{
/* The Libraries */
if ((GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 0L)) == NULL)
return FALSE;
if ((DiskfontBase = OpenLibrary("diskfont.library",0L)) == NULL)
return FALSE;
if ((IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 0L)) == NULL)
return FALSE;
/* The Devices */
if ((OpenDevice("console.device", -1L, request, 0L)) != 0L)
return FALSE;
if ((port->mp_SigBit = AllocSignal(-1L)) < 0)
return FALSE;
port->mp_SigTask = (struct Task *) FindTask((char *) NULL);
if (port->mp_SigTask->tc_Node.ln_Type != NT_PROCESS)
return FALSE;
return TRUE;
}
/* This function frees up dynamically opened things, like the devices
and the libraries, opened above. */
void ShutDown()
{
if (request->io_Device != NULL) {
if (port->mp_SigBit != -1) FreeSignal((long)port->mp_SigBit);
CloseDevice(request);
}
if (IntuitionBase != NULL) CloseLibrary(IntuitionBase);
if (DiskfontBase != NULL) CloseLibrary(DiskfontBase);
if (GfxBase != NULL) CloseLibrary(GfxBase);
}
/* ========================================================================= */
/* Attribute based functions. */
/* This function allocates space for the given font descriptor, converting
the point size into a numeric form at the same time. */
struct TextAttr *AllocAttr(fontname, pointname)
char *fontname, *pointname;
{
short point;
char *str;
struct TextAttr *attr = NULL;
attr = (struct TextAttr *) AllocMem((long)sizeof(*attr),0L);
if (pointname == NULL)
point = 8;
else
point = atoi(pointname);
str = (char *) AllocMem((long)(strlen(fontname)+6),0L);
strcpy(str,fontname);
strcat(str,".font");
attr->ta_Name = (STRPTR) str;
attr->ta_YSize = point;
attr->ta_Style = 0;
attr->ta_Flags = 0;
return attr;
}
/* This function frees a TextAttr allocated with AllocAttr(). */
void FreeAttr(attr)
struct TextAttr *attr;
{
if (attr == NULL)
return;
FreeMem(attr->ta_Name, (long)strlen(attr->ta_Name));
FreeMem(attr,(long)sizeof(*attr));
}
/* ========================================================================= */
/* This function allocates a packet and associated info block. It returns
a pointer to this packet if successful, NULL otherwise. */
struct StandardPacket *AllocInfoPacket()
{
struct StandardPacket *pac = NULL;
struct InfoData *inf = NULL;
pac = (struct StandardPacket *) AllocMem((long)sizeof(*pac), MEMF_CLEAR);
if (pac == NULL)
return NULL;
inf = (struct InfoData *) AllocMem((long)sizeof(*inf), MEMF_CLEAR);
if (inf == NULL) {
FreeMem(pac,(long)sizeof(*pac));
return NULL;
}
pac->sp_Msg.mn_Node.ln_Name = (char *) &(pac->sp_Pkt);
pac->sp_Pkt.dp_Link = &(pac->sp_Msg);
pac->sp_Pkt.dp_BufAddr = ((ULONG) inf) >> 2;
pac->sp_Pkt.dp_Type = ACTION_DISK_INFO;
return pac;
}
/* ========================================================================= */
/* This function gets the Window pointer for the current console. It
takes the message port for the console. It uses the fact that the I/O
device's message port points to the process associated with this CLI.
This process needs a console window, and it should have a pointer to a
message port for this purpose. We use DOS packets to request an
InfoData block on this console window. The window pointer is passed
back as the volume name of the console. We're getting into DOS, so look
out for BCPL pointers and longword alignment! */
struct Window *GetConsoleWindow(port)
struct MsgPort *port;
{
struct MsgPort *cp; /* Console port */
struct InfoData *inf; /* Packet data block */
struct StandardPacket *pac = NULL; /* Packet for DOS request */
struct Window *w = NULL; /* Resulting Window */
cp = (struct MsgPort *)((struct Process *)port->mp_SigTask)->pr_ConsoleTask;
if (cp == 0)
return NULL;
if ((pac = AllocInfoPacket()) == NULL)
return NULL;
pac->sp_Pkt.dp_Port = port;
inf = (struct InfoData *) (((ULONG) pac->sp_Pkt.dp_BufAddr) << 2);
PutMsg(cp, pac);
WaitPort(port);
w = (struct Window *) inf->id_VolumeNode;
FreeMem(inf, (long)sizeof(*inf));
FreeMem(pac, (long)sizeof(*pac));
return w;
}
/* ========================================================================= */
/* This function tries to get a requested font from an attribute descriptor;
it returns FALSE if the font doesn't exist. */
struct TextFont *GetFont(attr)
struct TextAttr *attr;
{
struct TextFont *font;
if ((font = OpenDiskFont(attr)) != NULL)
return font;
/* ky */
/* OpenDiskFont() will use an in-memory font if it exists... */
/* so the following call should not be needed */
/* if ((font = OpenFont(attr)) != NULL)
return font; */
return NULL;
}
/* ========================================================================= */
/* The main function */
main(argc, argv)
int argc;
char *argv[];
{
short i;
BOOL printmode = FALSE;
BOOL mode_screen = FALSE;
BOOL mode_title = FALSE;
BOOL mode_window = FALSE;
struct TextAttr *attr = NULL;
struct TextFont *newfont, *oldfont;
/* Automatic help command */
if (argc == 1)
printmode = TRUE;
else if (argv[1][0] == '?') {
printf("SetFont 2.0 by Dave Haynie; mods by Keith Young\n\n");
printf("Usage: SetFont [fontname [point [place]]], where\n\n");
printf(" \2331mfontname\2330m is the font's name (e.g. \"topaz\")\n");
printf(" \2331mpoint\2330m is the point size (default is 8)\n");
printf(" \2331mplace\2330m pick the place, one or more of:\n");
printf(" \2331mSCREEN\2330m set the screen font only\n");
printf(" \2331mTITLES\2330m set the screen titles only\n");
printf(" \2331mWINDOW\2330m set the window's font only\n\n");
printf("If no \2331mplace\2330m switch is given, everything is set.\n");
exit(10);
}
/* Process the command-line arguments, AmigaDOS style. */
for (i=3; i<argc; i++) {
if (argv[i][0] == 'T' || argv[i][0] == 't')
mode_title = TRUE;
else if (argv[i][0] == 'S' || argv[i][0] == 's')
mode_screen = TRUE;
else if (argv[i][0] == 'W' || argv[i][0] == 'w')
mode_window = TRUE;
}
if (!mode_title && !mode_screen && !mode_window)
mode_title = mode_screen = mode_window = TRUE;
/* First all, we've got to open all the good stuff. */
if (!OpenUp() || (window=GetConsoleWindow(port)) == NULL) {
ShutDown();
exit(10);
}
/* Process the informational print mode, real simple */
if (printmode) {
printf("SetFont 2.0 by Dave Haynie; mods by Keith Young\n\n");
attr = window->WScreen->Font;
printf("Screen Font: %s (%ld) ", attr->ta_Name, attr->ta_YSize);
printf("Style %ld, Flags %ld\n", attr->ta_Style, attr->ta_Flags);
ShutDown();
exit(0);
}
/* Get the attribute and font, where available. */
attr = AllocAttr(argv[1], argv[2]);
if ((newfont = GetFont(attr)) == NULL) {
printf("Error: Font not found\n");
FreeAttr(attr);
ShutDown();
exit(10);
}
/* Here's where the various options are processed individually. */
/* The screen titling font is changed via a SetFont() call to the
screen's RastPort. */
if (mode_title) {
oldfont = window->WScreen->RastPort.Font;
if( SetFont(&(window->WScreen->RastPort),newfont) ) {
/* ky */ /* the screen's BarLayer->rp also needs to be SetFont'd so
that the title-bar is displayed correctly... note that
Intuition (currently) also uses this font pointer for string
gadgets (and most other gadget text), menu titles, and
a few other places. We also need to update the screen's
BarHeight (this fixes the display of the title-bar, but
doesn't adjust the drag-gadget attached to it... that
might make a nice addition to this routine, I'll leave
that as "an excersize left for the programmer..." :-) */
/* ky */ if( SetFont(window->WScreen->BarLayer->rp, newfont) ) {
window->WScreen->BarHeight = newfont->tf_YSize + 2;
window->WScreen->BarLayer->bounds.MaxY = newfont->tf_YSize + 2;
}
CloseFont(oldfont);
}
}
/* If the current font is the same font, we can just change the point
size attribute value. If its a completely new font, the entire
attribute pointer is reassigned. This may not be necessary, but it
works this way, and I've had trouble with other schemes. */
/* ky */ /* each Screen structure has a struct TextAttr *Font in it...
after a fair ammount of investigating, I've found out that
(for screens that don't specify a font to use in their
NewScreen struct) this pointer (currently, under 1.3) points
to... IntuitionBase->SysFont (an INTUITIONPRIVATE field btw :)
So... it appears that when a new screen is opened, that doesn't
ask for a specific font in it's NewScreen struct, it uses this
TextAttr.
Dave's code reassigned the entire attribute pointer if it
was a new font name, this caused the screen to no longer
point at IntuitionBase->SysFont. What I do is just (effectively)
change IntuitionBase->SysFont.ta_Name to point to the new font
name and adjust the ta_YSize.
And now for the caveat/feature... any new screens opened
that don't specify a font will use this new font. Good if that's
what you want... Bad if the program doesn't handle it well :) */
if (mode_screen) {
if (strcmp(window->WScreen->Font->ta_Name,attr->ta_Name) == 0) {
window->WScreen->Font->ta_YSize = attr->ta_YSize;
FreeAttr(attr);
}
else {
/* ky */ window->WScreen->Font->ta_Name = attr->ta_Name;
/* ky */ window->WScreen->Font->ta_YSize = attr->ta_YSize;
}
}
/* The window font is changed via a SetFont() call to the window's
RastPort, much in the same way that the screen's titling fonts are
changed. Additionally, the console device must be reset to force
the ConUnit to be rebuit, which draws the new font from the
window. */
if (mode_window) {
oldfont = window->RPort->Font;
if( SetFont(window->RPort,newfont) ) {
/* ky */ /* again, we need to adjust the title-bar... */
window->BorderTop = newfont->tf_YSize + 2 + 1;
CloseFont(oldfont);
}
/* ky */ /* now comes the ConUnit rebuild (via the printf("\033c"))...
this (unfortunately) clears the screen, but it also doesn't
'quite' clean up the top of the window (title-bar area)
if we are using a new height font. Since the window will be
cleared anyway, I've added a RectFill() of my own, to clean
up the window. */
SetAPen(window->RPort, 0L);
RectFill( window->RPort, 2L, (long)(window->BorderTop-2),
(long)(window->Width-3),
(long)(window->Height - window->BorderBottom));
printf("\033c");
RefreshWindowFrame(window);
}
/* ky */ /* there used to be a 'CloseFont( newfont )' here... but
since we need it open (cause we are using it) it should
not be closed */
ShutDown();
exit(0);
}